/*
 * Copyright (c) 2010, Yawning <yawninglol at gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   * Neither the name of the Mew Developers nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

package yawning.mew.character;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * Base Character Definition.
 *
 * Note: If you add stats to this, update ToonToonBuilder or Yawning will kill you.
 *
 * @author Yawning <yawninglol at gmail.com>
 */
public class Toon {
    public int level;
    public Clazz mClass;
    public Race mRace;

    public int strength;
    public int agility;
    public int stamina;
    public int intellect;
    public int spirit;
    public int armor;
    public int bonusArmor;

    public int attackPower;
    public int mDodgeRating;
    public int mParryRating;
    public int hasteRating;
    public int critRating;
    public int hitRating;
    public int expertiseRating;
    public int masteryRating;
    public int mResilienceRating;

    public int weaponTop;
    public int weaponBottom;
    public int weaponSpeed;

    // TODO: There should be a cleaner way to handle tier bonus
    public boolean tier_10_2pc;
    public boolean tier_10_4pc;
    public boolean tier_11_2pc;
    public boolean tier_11_4pc;
    public boolean tier_12_2pc;
    public boolean tier_12_4pc;
    public boolean tier_13_2pc;
    public boolean tier_13_4pc;

    public boolean pvp_gloves;

    public boolean isArmorSpec;
    public boolean isWeaponRacial;
    public MetaGem mMetaGem;
    public TalentTree mTalentSpec;

    Set<Glyph> mGlyphs = new HashSet<Glyph>();
    byte[] mTalents = new byte[100];
    Map<Profession,Integer> mProfessions = new HashMap<Profession,Integer>();

    public boolean hasGlyph(Glyph g) {
        return mGlyphs.contains(g);
    }

    /**
     * Method that removes a specific glyph.
     * @param g
     * 	glyph to remove
     */
    public void removeGlyph(Glyph g)
    {
    	mGlyphs.remove(g);
    }

    /**
     * Method that adds a specific glyph.
     *
     * Note: this method does verify if the maximum amount of glyphs of a type are allready affected on the character.
     * @param g
     * 	glyph to add
     * @return
     * 	If the glyph was added or not.
     */
    public boolean addGlyph(Glyph g)
    {
    	Iterator<Glyph> it = mGlyphs.iterator();
    	int countType = 0;


    	while(it.hasNext() && countType<3)
    	{
    			Glyph gt = it.next();
    			if(gt.getType() == g.getType())
    			{
    				countType++;
    			}
    	}

    	if(countType==3)
    	{
    		return false;
    	}

    	mGlyphs.add(g);
    	return true;
    }

    public boolean hasProfession(Profession p, int skill) {
    	if (mProfessions.containsKey(p) && mProfessions.get(p) >= skill)
    		return true;

    	return false;
    }

    public boolean addProfession(Profession p, int skill) {
    	if (skill > 0) mProfessions.put(p, skill);

    	return true;
    }

    public void removeProfession(Profession p) {
    	mProfessions.remove(p);
    }

    public int getTalent(Talent t) {
    	return mTalents[t.getId()];
    }

    @Override
    public String toString() {
    	StringBuffer sb = new StringBuffer();

    	sb.append("Level: ").append(level).append('\n');
    	sb.append("Class: ").append(mClass).append('\n');
    	sb.append("Race: ").append(mRace).append('\n');

    	sb.append("Meta Gem: ").append(mMetaGem).append('\n');

    	sb.append("Strength: ").append(strength).append('\n');
    	sb.append("Agility: ").append(agility).append('\n');
    	sb.append("Stamina: ").append(stamina).append('\n');
    	sb.append("Intellect: ").append(intellect).append('\n');
    	sb.append("Spirit: ").append(spirit).append('\n');
    	sb.append("Armor: ").append(armor).append('\n');
    	sb.append("Bonus Armor: ").append(bonusArmor).append('\n');

    	sb.append("Attack Power: ").append(attackPower).append('\n');
    	sb.append("Dodge Rating: ").append(mDodgeRating).append('\n');
    	sb.append("Parry Rating: ").append(mParryRating).append('\n');
    	sb.append("Haste Rating: ").append(hasteRating).append('\n');
    	sb.append("Crit Rating: ").append(critRating).append('\n');
    	sb.append("Hit Rating: ").append(hitRating).append('\n');
    	sb.append("Expertise Rating: ").append(expertiseRating).append('\n');
    	sb.append("Mastery Rating: ").append(masteryRating).append('\n');
    	sb.append("Resilience Rating: ").append(mResilienceRating).append('\n');

    	sb.append("Weapon Top: ").append(weaponTop).append('\n');
    	sb.append("Weapon Bottom: ").append(weaponBottom).append('\n');
    	sb.append("Weapon Speed: ").append(weaponSpeed).append('\n');

    	sb.append("Armor Spec: ").append(isArmorSpec).append('\n');
    	sb.append("Weapon Racial ").append(isWeaponRacial).append('\n');

    	sb.append("Professions: \n");
    	for (Map.Entry<Profession,Integer> e : mProfessions.entrySet()) {
    		sb.append("  ").append(e.getKey()).append(": ").append(e.getValue()).append('\n');
    	}

    	sb.append("Glyphs: \n");
    	for (Glyph g : mGlyphs) sb.append("  ").append(g).append('\n');

    	sb.append("Talent spec: ").append(mTalentSpec).append('\n');
    	Talent[] talents = mClass.getTalents();
    	for (int i = 0; i < talents.length; i++) if (mTalents[i] > 0) sb.append("  ").append(talents[i]).append(": ").append((int)mTalents[i]).append('\n');

    	return sb.toString();
    }
}
